// JORGE FERNANDO GOMEZ
// 1259371
// 189631
// LEC A1
// MARTIN MÜLLER
// D02
// YANG LIU


#line 10 "process.c"

#include <ctype.h>

#include "util.h"
#include "process.h"


/* classifyLines() takes a Line * Lines, and tags each line stored according
 * to its first keyword.  Keywords must not have leading whitespace, or
 * classifyLines() will fail.  Returns 0 if successful, or 1 if a line
 * contains bad format. */
int classifyLines ( Line * Lines ) {

    char linebuf[11+1];
    int currentLine = 0;
    int tester;


    for ( currentLine = 0; currentLine < inputFileLength; currentLine++ ) {

        memset(linebuf, '\0', 11+1);
        tester = sscanf(Lines[currentLine].lineString, " %s", linebuf);

        if ( tester == -1 ) {
            Lines[currentLine].commandType = BLANK;
            continue;
        }


        /* Tag each line depending on keyword found for easier processing. */
        if ( strncmp( linebuf, "#", strlen("#")) == 0 ) {
            Lines[currentLine].commandType = COMMENT;
        }
        else if ( strncmp( linebuf, "Figure",
                    strlen("Figure")) == 0 ) {
            Lines[currentLine].commandType = FIGURE;
        }
        else if ( strncmp( linebuf, "End",
                    strlen("End")) == 0 ) {
            Lines[currentLine].commandType = END;
        }
        else if ( strncmp( linebuf, "drawFigure",
                    strlen("drawFigure")) == 0 ) {
            Lines[currentLine].commandType = DRAWFIGURE;
        }
        else if ( strncmp( linebuf, "draw",
                    strlen("draw")) == 0 ) {
            Lines[currentLine].commandType = DRAW;
        }
        else if ( strncmp( linebuf, "printFigure",
                    strlen("printFigure")) == 0 ) {
            Lines[currentLine].commandType = PRINTFIGURE;
        }
        else if ( strncmp( linebuf, "translate",
                    strlen("translate")) == 0 ) {
            Lines[currentLine].commandType = TRANSLATE;
        }
        else if ( strncmp( linebuf, "child",
                    strlen("child")) == 0 ) {
            Lines[currentLine].commandType = CHILD;
        }
        else if ( strncmp( linebuf, "rotate",
                    strlen("rotate")) == 0 ) {
            Lines[currentLine].commandType = ROTATE;
        }
        else
            return 1;

    }

    return 0;
}

/* getFigureSpecs() takes a Line * Lines, and checks for a tag FIGURES
 * inside each line.  When a tag is found, properties about the figure
 * defined at that line are stored in FigStack * Figures.
 * It returns the last line number it last explored, or -1 if it couldn't
 * possibly begun looking for Figure definitions. */
int getFigureSpecs (Line * Lines, FigStack * Figures, int currentLine ) {

    /* Local string buffers. */
    char tempbuf[6+1];
    char localFigName[MAXLEN_FIG+1];

    int figIndex;   /* Holds index for previously defined figure. */
    int strlength;
    int count;

    /* Look for up to permitted boundaries. */
    if ( currentLine < inputFileLength-2 ) {

        sscanf(Lines[currentLine].lineString, " %s%s",
                tempbuf, localFigName);

        strlength = strlen(localFigName);

        /* Check whether a figure figexists or not. If it does not exist and
         * we haven't gone past our figure limit, store it.  If it does
         * exist, then it's being redifined, so clearfig it and updatefig it.
         * In both cases we look for draw commands (if any). */
        if ( !(figexists(localFigName, Figures)) ) {

            addFig(Figures, localFigName);
            updatefig( Lines[currentLine].lineString,
                    Figures, Figures->figureCount, 2);

            currentLine++;

            while ( Lines[currentLine].commandType != END &&
                    currentLine < inputFileLength-2 ) {

                if ( Lines[currentLine].commandType == DRAW ) {

                    count = sscanf(Lines[currentLine].lineString,
                            " %*s %c %c", &tempbuf[0], &tempbuf[1]);
                    if (count == 2)
                        updatefig( Lines[currentLine].lineString,
                                Figures, Figures->figureCount, 1);
                    else {
                        Figures->figureCount++;
                        kill(__LINE__);
                    }
                }

                else if ( Lines[currentLine].commandType != COMMENT &&
                          Lines[currentLine].commandType != BLANK ) {
                    Figures->figureCount++;
                    kill(__LINE__);
                }

                currentLine++;
            }

            char * temp = substr(Lines[currentLine].lineString, 11, strlength);

            if ( strncmp( temp, localFigName, strlength ) != 0 ) {
                free (temp);
                Figures->figureCount++;
                kill(__LINE__);
            }
            free(temp);

            /* Keep track of figures defined and stored. */
            Figures->figureCount++;
        }
        else if ( figexists(localFigName, Figures) ) {

            /* Get index of a previously defined figure. */
            figIndex = getFigIndex(localFigName, Figures);

            updatefig(Lines[currentLine].lineString, Figures, figIndex, 2);
            clearfig(Figures, figIndex, 0);
            currentLine++;

            while ( Lines[currentLine].commandType != END &&
                    currentLine < inputFileLength-2 ) {

                if ( Lines[currentLine].commandType == DRAW ) {
                    count = sscanf(Lines[currentLine].lineString,
                            " %*s %c %c", &tempbuf[0], &tempbuf[1]);
                    if (count == 2)
                        updatefig( Lines[currentLine].lineString,
                                Figures, figIndex, 1);
                    else {
                        Figures->figureCount++;
                        kill(__LINE__);
                    }
                }

                else if ( Lines[currentLine].commandType != COMMENT &&
                          Lines[currentLine].commandType != BLANK )
                    kill(__LINE__);

                currentLine++;
            }

            char * temp = substr(Lines[currentLine].lineString, 11, strlength);

            if ( strncmp( temp, localFigName, strlength ) != 0 ) {
                free(temp);
                kill(__LINE__);
            }
            free(temp);
        }
        return currentLine;
    }
    return -1;
}

/* executeCommands() goes through each line in Lines and checks for their tag.
 * Depending on each tag, a different action is taken. */
void executeCommands ( FILE * outputFile, Line * Lines, FigStack * Figures ) {

    char tempbuf[11+1];
    char figureName[MAXLEN_FIG+1];

    int figIndex = 0;
    int currentLine = 0;
    int tester;

    double tx, ty;      /* Deltas (x, y). */

    /* Go through each line, and do something depending on the keyword. */
    for ( currentLine = 0; currentLine < inputFileLength; currentLine++ )

        switch ( Lines[currentLine].commandType ) {

            case FIGURE: /* getFigureSpecs() returns the last line it read. */
                currentLine =
                    getFigureSpecs(Lines, Figures, currentLine);
                break;

            case TRANSLATE:
            case ROTATE:
            case PRINTFIGURE:
            case DRAWFIGURE:

                tester = sscanf(Lines[currentLine].lineString, "%s%s%lf%lf",
                                tempbuf, figureName, &tx, &ty);

                if ( tester != 2 && tester != 4 )
                    if ( Lines[currentLine].commandType != ROTATE )
                        kill(__LINE__);

                figIndex = getFigIndex(figureName, Figures);

                if ( figIndex == -1 )
                    kill(__LINE__);

                if ( Lines[currentLine].commandType == TRANSLATE )
                    translateFigure(Figures, figIndex, tx, ty);
                else if ( Lines[currentLine].commandType == ROTATE )
                    rotateFigure(Figures, figIndex, tx);
                else
                    drawPrintFigure(outputFile, Figures, figIndex,
                            Lines[currentLine].commandType);

                break;

            case COMMENT:
                printf("%s\n", Lines[currentLine].lineString);
                break;

            case CHILD:
                sendChildCommands(outputFile, Lines, currentLine);
                break;

            case DRAW:
                kill(__LINE__);
                break;
            default:
                break;
        }

}


/* drawPrintFigure() takes an index to retrieve figure definitions from
 * Figures->figProperties array.
 * Commands are piped to outputFile or printed to stdout
 * depending on type. */
void drawPrintFigure( FILE * outputFile, FigStack * Figures,
                      int figIndex, int type) {

    int drawCount;
    double x, y;          /* Current (x, y) pen position. */
    double dx, dy;        /* Deltas (x, y) for current pen position. */
    double xNew, yNew;    /* New (x, y) pen position after deltas are applied. */

    /* Retrieve data. */
    drawCount = Figures->figProperties[figIndex].drawCount;
    x = Figures->figProperties[figIndex].x;
    y = Figures->figProperties[figIndex].y;

    /* Carry out appropiate actions depending on command type. */
    if (type == PRINTFIGURE) {
        printf("Print Figure %s =\n",
                Figures->figProperties[figIndex].figureName);

        /* Do not print anything if there were no draw commands. */
        if ( Figures->figProperties[figIndex].drawCount )
            printf("%g %g\n", x, y);

    }

    int i;  /* Repeat up to the amount of draw commands found. */
    for (i = 0; i < drawCount; i++) {

        /* Retrieve deltas (x, y). */
        dx = Figures->figProperties[figIndex].dx[i];
        dy = Figures->figProperties[figIndex].dy[i];
        xNew = x + dx;
        yNew = y + dy;

        /* Carry out appropriate action according to specification. */
        if (type == PRINTFIGURE)
            printf("%g %g\n", xNew, yNew);
        else
            fprintf(outputFile, "drawSegment %ld %ld %ld %ld\n",
                    lround(x), lround(y), lround(xNew), lround(yNew));

        x = xNew;
        y = yNew;
    }

    if (type == PRINTFIGURE)
        printf("End Figure %s\n",
                Figures->figProperties[figIndex].figureName);

}

/* translateFigure() transforms Figures->figProperties at index
 * by adding the deltas (tx, ty) to the current stored (x, y) values. */
void translateFigure ( FigStack * Figures, int figIndex,
                       double tx, double ty) {

    /* Add (tx, ty) to current (x, y). */
    Figures->figProperties[figIndex].x += tx;
    Figures->figProperties[figIndex].y += ty;

}

/* rotateFigure() takes angle as parameter and rotates all the points
 * in a figure defined at figIndex in Figures->figProperties. */
void rotateFigure ( FigStack * Figures, int figIndex, double angle ) {

    /* Hold rotated (x, y) points. */
    double rx, ry;
    double x, y;

    /* Get amount of points (draw commands). */
    int drawCount = Figures->figProperties[figIndex].drawCount;

    if ( drawCount == 0 )
        return;

    double angleRadians = angle * PI / 180.0;

    x = Figures->figProperties[figIndex].x;
    y = Figures->figProperties[figIndex].y;

    rx = ( cos(angleRadians)*x ) - ( sin(angleRadians)*y );
    ry = ( sin(angleRadians)*x ) + ( cos(angleRadians)*y );

    /* Assign the new rotated points to starting (x, y). */
    Figures->figProperties[figIndex].x = rx;
    Figures->figProperties[figIndex].y = ry;

    int i;

    /* And do the same for each point in the figure. */
    for ( i = 0; i < drawCount; i++ ) {
        x = Figures->figProperties[figIndex].dx[i];
        y = Figures->figProperties[figIndex].dy[i];

        rx = ( cos(angleRadians)*x ) - ( sin(angleRadians)*y );
        ry = ( sin(angleRadians)*x ) + ( cos(angleRadians)*y );

        Figures->figProperties[figIndex].dx[i] = rx;
        Figures->figProperties[figIndex].dy[i] = ry;
    }
}


/* sendChildCommands() pipes to outputFile commands following the "child"
 * keyword up to the end of the string found in Line * Lines at lineNumber. */
void sendChildCommands (FILE * outputFile, Line * Lines, int currentLine) {

    char * childCommands;

    int strLength = strlen(Lines[currentLine].lineString);

    /* Get substring of commands which should follow child. */
    childCommands = substr(Lines[currentLine].lineString, 5, strLength-5);

    /* Send substring of commands to Sketchpad.jar. */
    fprintf(outputFile, "%s\n", childCommands);

    free(childCommands);

}

